#include "config.h"

#include <errno.h>
#include <unistd.h>
#include <rpc/rpc.h>
#include <rpc/svc.h>
#include <rpc/pmap_clnt.h>
#include <sys/poll.h>

#define DBG_SUBSYS S_LIBINTERFACE

#include "sysy_lib.h"
#include "job_dock.h"
#include "nfs_events.h"
#include "nfs_state_machine.h"
#include "nfs_job_context.h"
#include "xdr_nfs.h"
#include "sunrpc_passive.h"
#include "sunrpc_proto.h"
#include "ynfs_conf.h"
#include "ynet_rpc.h"
#include "dbg.h"

#define	RQCRED_SIZE	400	/* this size is excessive */

extern worker_handler_t jobtracker;

typedef int (*hash_args_t)(void*);

typedef void (*nfs_handler_func)(const sockid_t *sockid, uint32_t xid, nfs_arg_t *nfs_arg, buffer_t *_buf);

void mnt_event_handler(const sockid_t *sockid, sunrpc_request_t *req, buffer_t *_buf)
{
        int ret;
        nfs_handler_func handler = NULL;
        xdr_arg_t xdr_arg = NULL;
        char *name = NULL;
        xdr_t xdr;
        nfs_arg_t arg;

        DBUG("mnt\n");
        
        switch (req->procedure) {
        case MNT_NULL:
                handler = mount_null_svc;
                xdr_arg = (xdr_arg_t)__xdr_void;
                name = "MNT_NULL";
                break;
        case MNT_MNT:
                handler = mount_mnt_svc;
                xdr_arg = (xdr_arg_t)xdr_dirpath;
                name = "MNT_MNT";
                break;
        case MNT_DUMP:
                handler = mount_dump_svc;
                xdr_arg = (xdr_arg_t)__xdr_void;
                name = "MNT_DUMP";
                break;
        case MNT_UMNT:
                handler = mount_umnt_svc;
                xdr_arg = (xdr_arg_t)xdr_dirpath;
                name = "MNT_UMNT";
                break;
        case MNT_UMNTALL:
                handler = NULL;
                xdr_arg = NULL;
                name = "MNT_UMNTALL";
                break;
        case MNT_EXPORT:
                handler = mount_export_svc;
                xdr_arg = (xdr_arg_t)__xdr_void;
                name = "MNT_EXPORT";
                break;
        default:
                UNIMPLEMENTED(__DUMP__);
        }

        DBUG("<-------------------new procedure %s------------------>\n", name);

        xdr.op = __XDR_DECODE;
        xdr.buf = _buf;

        if (xdr_arg) {
                ret = xdr_arg(&xdr, &arg);
                if (unlikely(ret))
                        UNIMPLEMENTED(__DUMP__);
        }

        handler(sockid, req->xid, &arg, _buf);
}

void acl_event_handler(const sockid_t *sockid, sunrpc_request_t *req, buffer_t *_buf)
{
        nfs_handler_func handler = NULL;

        (void) _buf;

        switch (req->procedure) {
        case ACL_NULL:
                handler = acl_null_svc;
                break;
        default:
                UNIMPLEMENTED(__DUMP__);
        }

        handler(sockid, req->xid, NULL, _buf);
}

void nfs_event_handler(const sockid_t *sockid, sunrpc_request_t *req, buffer_t *_buf)
{
        int ret, urgent __attribute__((unused)) = 0;
        nfs_handler_func handler = NULL;
        xdr_arg_t xdr_arg = NULL;
        xdr_t xdr;
        nfs_arg_t arg;

        switch (req->procedure) {
        case NFS3_NULL:
                handler = nfs3_null_svc;
                xdr_arg = NULL;
                schedule_task_setname("nfs_null");
                break;
        case NFS3_GETATTR:
                handler = nfs3_getattr_svc;
                xdr_arg = (xdr_arg_t)xdr_getattrargs;
                urgent = 1;
                schedule_task_setname("nfs_getattr");
                break;
        case NFS3_SETATTR:
                handler = nfs3_setattr_svc;
                xdr_arg = (xdr_arg_t)xdr_setattrargs;
                schedule_task_setname("nfs_setattr");
                break;
        case NFS3_LOOKUP:
                handler = nfs3_lookup_svc;
                xdr_arg = (xdr_arg_t)xdr_lookupargs;
                urgent = 1;
                schedule_task_setname("nfs_lookup");
                break;
        case NFS3_ACCESS:
                handler = nfs3_access_svc;
                xdr_arg = (xdr_arg_t)xdr_accessargs;
                urgent = 1;
                schedule_task_setname("nfs_access");
                break;
        case NFS3_READLINK:
                handler = nfs3_readlink_svc;
                xdr_arg = (xdr_arg_t)xdr_readlinkargs;
                schedule_task_setname("nfs_readlink");
                break;
        case NFS3_READ:
                handler = nfs3_read_svc;
                xdr_arg = (xdr_arg_t)xdr_readargs;
                schedule_task_setname("nfs_read");
                break;
        case NFS3_WRITE:
                handler = nfs3_write_svc;
                xdr_arg = (xdr_arg_t)xdr_writeargs;
                urgent = 1;
                schedule_task_setname("nfs_write");
                break;
        case NFS3_CREATE:
                handler = nfs3_create_svc;
                xdr_arg = (xdr_arg_t)xdr_createargs;
                schedule_task_setname("nfs_create");
                break;
        case NFS3_MKDIR:
                handler = nfs3_mkdir_svc;
                xdr_arg = (xdr_arg_t)xdr_mkdirargs;
                schedule_task_setname("nfs_mkdir");
                break;
        case NFS3_SYMLINK:
                handler = nfs3_symlink_svc;
                xdr_arg = (xdr_arg_t)xdr_symlinkargs;
                schedule_task_setname("nfs_symlink");
                break;
        case NFS3_MKNOD:
                handler = NULL;
                xdr_arg = NULL;
                schedule_task_setname("nfs_mknod");
                break;
        case NFS3_REMOVE:
                handler = nfs3_remove_svc;
                xdr_arg = (xdr_arg_t)xdr_removeargs;
                schedule_task_setname("nfs_remove");
                break;
        case NFS3_RMDIR:
                handler = nfs3_rmdir_svc;
                xdr_arg = (xdr_arg_t)xdr_rmdirargs;
                schedule_task_setname("nfs_rmdir");
                break;
        case NFS3_RENAME:
                handler = nfs3_rename_svc;
                xdr_arg = (xdr_arg_t)xdr_renameargs;
                schedule_task_setname("nfs_rename");
                break;
        case NFS3_LINK:
                handler = nfs3_link_svc;
                xdr_arg = (xdr_arg_t)xdr_LINK3args;
                schedule_task_setname("nfs_link");
                break;
        case NFS3_READDIR:
                handler = nfs3_readdir_svc;
                xdr_arg = (xdr_arg_t)xdr_readdirargs;
                urgent = 1;
                schedule_task_setname("nfs_readdir");
                break;
        case NFS3_READDIRPLUS:
                handler = nfs3_readdirplus_svc;
                xdr_arg = (xdr_arg_t)xdr_readdirplusargs;
                urgent = 1;
                schedule_task_setname("nfs_readdirplus");
                break;
        case NFS3_FSSTAT:
                handler = nfs3_fsstat_svc;
                xdr_arg = (xdr_arg_t)xdr_fsstatargs;
                schedule_task_setname("nfs_fsstat");
                break;
        case NFS3_FSINFO:
                handler = nfs3_fsinfo_svc;
                xdr_arg = (xdr_arg_t)xdr_fsinfoargs;
                schedule_task_setname("nfs_fsinfo");
                break;
        case NFS3_PATHCONF:
                handler = nfs3_pathconf_svc;
                xdr_arg = (xdr_arg_t)xdr_pathconf3_args;
                schedule_task_setname("nfs_pathconf");
                break;
        case NFS3_COMMIT:
                handler = nfs3_commit_svc;
                xdr_arg = (xdr_arg_t)xdr_commitargs;
                schedule_task_setname("nfs_commit");
                break;
        default:
                UNIMPLEMENTED(__DUMP__);
        }

        xdr.op = __XDR_DECODE;
        xdr.buf = _buf;

        DBUG("op %u\n", req->procedure);
        
        if (xdr_arg) {
                ret = xdr_arg(&xdr, &arg);
                if (unlikely(ret))
                        UNIMPLEMENTED(__DUMP__);
        }

        handler(sockid, req->xid, &arg, _buf);
}
